{# The one table macro. A page declares columns and hands over rows; it never writes a by hand. {% from "components/macros/table.html" import data_table %} {{ data_table(columns, rows, empty="No transactions yet") }} ``columns``: list of ``{"key", "label", "kind", "align", "signed"}``. ``kind`` is ``text`` (default), ``money`` (minor units, honours the row's ``currency`` when it has one; ``signed`` adds a leading ``+`` and colours by sign, ``toned`` colours by sign without the plus), ``date``, ``int`` or ``status`` (the value is ``{"label", "tone"}``, rendered as a ``badge``); ``align`` is ``left`` (default) or ``right``. Rows are objects or dicts; a blank value renders as a dash. Zero rows render ``empty_state`` instead. ``row_id`` names each ```` (``row_id ~ "-" ~ row.id``) so an action can swap one row back; a ``{% call(row) data_table(...) %}`` block adds an actions column rendered per row. #} {% from "components/macros/feedback.html" import empty_state %} {% from "components/macros/layout.html" import badge %} {% macro _cell(row, col) -%} {%- set value = row[col.key] if row is mapping else row|attr(col.key) -%} {%- if value is none or value == "" -%} - {%- elif col.kind == "money" -%} {%- set currency = (row["currency"] if row is mapping and "currency" in row else row|attr("currency")) -%} {{ "+" if col.signed and value > 0 }}{{ value|money(currency if currency is string else "USD") }} {%- elif col.kind == "status" -%} {{ badge(value.label, value.tone) }} {%- elif col.kind == "date" -%} {{ value|short_date }} {%- elif col.kind == "int" -%} {{ "{:,}".format(value) }} {%- else -%} {{ value }} {%- endif -%} {%- endmacro %} {# The text colour of one cell: signed money reads by sign. #} {% macro _tone(row, col) -%} {%- set value = row[col.key] if row is mapping else row|attr(col.key) -%} {%- if col.kind == "money" and (col.signed or col.toned) and value is number and value != 0 -%} {{ "text-aegis-teal" if value > 0 else "text-error" }} {%- else -%} text-aegis-text {%- endif -%} {%- endmacro %} {# One row. ``id`` lets an action swap this row back by itself; ``oob`` marks it as an out-of-band answer (pattern 2); ``actions`` is a macro (a call block's ``caller``) rendering the trailing actions cell. #} {% macro table_row(columns, row, id=None, oob=False, actions=None) %} {# A row swapped out of band travels wrapped: a bare at the top of a response bound for anything but a table is thrown away by the HTML parser, and its cells spill into whatever was being swapped — a stray row loose in a dialog. htmx unwraps a template before it swaps, so this is the way to send one anywhere. #} {% if oob %}{% endif %} {% for col in columns %} {% endfor %} {% if actions %}{% endif %} {% if oob %}{% endif %} {% endmacro %} {% macro data_table(columns, rows, empty="Nothing here yet", row_id=None) %} {% if rows %}
{{ _cell(row, col) }}{{ actions(row) }}
{% for col in columns %} {% endfor %} {% if caller is defined %}{% endif %} {% for row in rows %} {{ table_row(columns, row, id=(row_id ~ "-" ~ (row["id"] if row is mapping else row.id)) if row_id else None, actions=caller if caller is defined else None) }} {% endfor %}
{{ col.label }}Actions
{% else %} {{ empty_state(empty) }} {% endif %} {% endmacro %} {# Page navigation for a listed table. ``pager`` is the route's ``{start, end, total, prev, next}`` (``None`` when one page); the links re-request the same URL and swap ``target`` in place. #} {% macro pager(pager, target) %} {% if pager %} {% endif %} {% endmacro %}